home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-20
/
rs0422.zip
/
ROSEZSW
/
UPCALLS.C
< prev
Wrap
C/C++ Source or Header
|
1990-08-04
|
17KB
|
658 lines
/*
* Copyright 1988 by the Radio Amateur Telecommunications Society
* and Thomas A. Moulton, W2VY
*
* This software may only be modified, copied, distributed or
* executed for non-profit purposes by individuals operating
* systems in the Amateur Radio Service. Credit to the
* author(s) and to the Radio Amateur Telecommunications Society
* must be made in modules where RATS provided software is used,
* and in any announcements and documentation.
*
* As a non-profit, research and development organization, the
* Radio Amateur Telecommunications Society distributes software
* in both executable and source forms. This policy is in place
* to encourage the development and distribution of OSI-based,
* networking tools. In order to protect the interests of the
* Society and the authors, we have placed some conditions
* of use on the software. Other groups are encouraged
* to place the same or similar guidelines on
* software they produce.
*
* The Radio Amateur Telecommunications Society reserves the right
* to specify and alter the terms under which software provided by
* the Society may be used. This policy is consistent with the
* objective of uniform and consistent "Open Systems Interconnections."
*
* All acceptable Amateur Radio related uses of this software
* will be outlined in the "ROSE Implementer's Guide". Individuals
* or organizations wishing to add to, or modify the provisions of
* the guide to accommodate local or evolutionary requirements
* should document the proposed change(s) and forward them to the
* Society. If accepted, written notification will be provided by
* the Society to the submitting organization or individual(s).
* The Society will then issue a "ROSE Implementer's Guide Change
* Notice". Periodically, the Society will re-issue the "ROSE
* Implementer's Guide" and incorporate the text of the change
* notices. This procedure has been put in to place to ensure
* compatibility between systems and to ensure their "Openness"
* and interoperability.
*
* No part of this software may be used in other packages
* without prior authorization from the author or the Society.
* Software incorporating this module, all or in part, must be
* provided to the Society prior to distribution or use by
* anyone not directly involved in testing of the revised
* environment. Current releases of the combined software must
* be provided to the Society in both source and executable
* forms. Adequate documention to produce an executable module
* from the provided source must also be included.
*
* Non-Amateur Radio non-profit uses may be authorized on a case
* by case basis. Inquiries for such use may be made in writing
* to the Society. Non-commercial uses consistent with the
* general principles of Open Systems Interconnection Reference
* Model will be generally considered with favor.
*
* Commercial licensing of the software is also available based
* on normal commercial terms. Licensing inquiries should be
* directed to the Society. Commercial licensing of the standard
* software will be done in situations which materially benefit
* the Amateur Radio Packet Network. Additional licensing is
* reserved by the individual authors.
*
* The Radio Amateur Telecommunications Society provides this software
* on an "as is" basis. The Society assumes no liability for
* loss incurred through the use of this software. Amateur Radio
* use of this software implies non-commercial and voluntary
* development, deployment and use of this software in a "Amateur",
* non-commercial service. Commercial users are encouraged to
* inspect their copies of the source code. Source code modification
* licenses are available if a combined Object and Source Code
* license was not originally established.
*
* The Society may be contacted by writing or calling at:
*
* The Radio Amateur Telecommunications Society
* 206 North Vivyen Street.
* Bergenfield, New Jersey 07621
*
* Telephone: 201-387-8896
*
*/
#include "data.h"
#include "buffer.h"
#include "iface.h"
#include "timer.h"
#include "ax25.h"
#include "ax25l2.h"
#include "l3struc.h"
#include "x25cause.h"
#include "l3calls.h"
#include "tx.h"
extern unsigned char node_addr[16];
extern unsigned char str_work[128];
extern struct datastr *l2_user_info; /* The message to send dummies */
extern struct ax25_addr L3CALL[];
extern unsigned char L3_MAXVC[];
#define L3SIZ 32
void rx_up_ignore(), tx_up_flush(), level3(), del_ax25();
int st_up_wait();
extern struct ax25_parms *l2parms, *l3parms;
extern unsigned char call_num;
int l2_clear(), l2_reset(), l2_send(), l2_recv(), NULLFCN();
struct datastr *mkpkt();
void rsrtco(), lnk_ign_fcn(), vc_clear();
int
lnk_cauz(axcb)
register struct axcb *axcb;
{
return ((axcb->parms->retry&&!axcb->n2cnt) ? Congestion+146 : DTE_Orig);
}
int
l2_st_up(axcbx, oldstate, newstate)
struct axcb *axcbx; /* Link */
unsigned char oldstate, newstate; /* Old and new states */
{
register struct VCS *vc;
static struct VCS *vcp;
static struct axcb *axcb;
static int c;
static unsigned char a, b;
struct VCS *new_vcs();
int callcmp();
axcb=axcbx;
puthex2("l2st",axcb,"->",newstate);
vc=axcb->llcn;
vcp= (vc ? vc->peer : (struct VCS *)NULL);
if ((newstate == 0) && vc) /* Link Reset */ {
if (vc->P == P4) /* Call in Data Transfer */ {
vc_reset(vc, DTE_Orig+146);
}
else tnc_attempt(axcb,vcp);
}
else {
if (newstate == 5) /* Connect occurred */ {
if (oldstate == 2) /* We made the call, notify peer */ {
if (vc) set_p(vc,P4,0); /* have a vc */
}
else if (oldstate == 1) /* Connect request */ {
if (!(vc=new_vcs())) return 0; /* No memory */
vcp=vc->peer;
vc->parent=axcb;
vc->lcn=0;
axcb->llcn = vc; /* insert_lcn(vc); */
vc_l2_pars(vc);
str_work[0]=0;
a=1;
b=0;
c=3;
do {
if (callcmp(&axcb->path[a],&L3CALL[0])) b=1;
if (callcmp(&axcb->path[a],&L3DIGI[0])) b=2;
if (b) /* If either callsign used */ {
str_work[0]=0;
l3_adr(&axcb->path[a-1],str_work);
if (str_work[0] == 4) /* Was DNIC */ {
l3_adr(&axcb->path[a-2],str_work);
c++;
}
if (!str_work[0]) /*Failed*/ {
free(vcp);
free(vc);
axcb->llcn = NULL;
return 0;
}
if (!(axcb->path[a].ssid&E)) /*More*/ {
memcpy(&vc->digi,&axcb->path[a+1],AXALEN);
}
if (a==c) /* Have destination digi */ {
memcpy(&vcp->digi,&axcb->path[1],AXALEN);
}
adr_copy(0,str_work,0,vcp->addr);
/* adr_copy(0,node_addr,0,vc->addr); */
break;
}
} while ( !(axcb->path[a++].ssid & E));
if (!b) return 0; /* Never Entered Loop */
mk_nsap(vcp,&axcb->myaddr);
mk_nsap(vc,axcb->path);
mk_rand(vc);
vcp->alt = 255; /* First time through call_request */
vc->P = P2; /* This link is in Call Request */
if (b == 2) vc->flags = vcp->flags = CLRONRESET;
tnc_attempt(axcb, vcp); /* Give message */
}
}
else {
if (newstate == 1) /* Disconnect occurred */ {
if (vcp) /* Have peer */ {
c = DTE_Orig;
if (axcb->parms->retry&& !axcb->n2cnt) {
c = Congestion+146;
if (oldstate == 2) c=Ship_Absent;
} else if (oldstate == 2) c=Number_Busy;
/* (*vc->CLEAR)(vc, DTE_Orig); */
set_p(vc, P7, c);
}
del_ax25(axcb);
}
}
}
return 1;
}
/* l3_rx_up => see Level3.c, level3() */
/* l3_tx_up => not used, may want to insure no vc's are flow controlled */
l3_st_up(lnk,oldstate,newstate)
register struct axcb *lnk;
unsigned char oldstate, newstate;
{
static struct VCS *vc, *lvc;
static int c;
unsigned char i;
void rx_up_wait();
int route_fail();
puthex2("l3st",lnk,"->",newstate);
if (newstate == 0) /* Link Reset */ {
if (lnk->R == R1) {
lvc = lnk->llcn;
while (lvc) /* More vc's to reset */ {
vc=lvc;
lvc=lvc->next;
if (vc->P == P4) vc_reset(vc, Net_Congest+146);
else vc_clear(vc, Congestion+146);
}
} else /* Link Reset during L3 Restart */ {
if (lnk->R != R0) /* Restart again */ {
rsrtco(lnk);
lnk->R = R0;
lnk->coll=0;
} else if (lnk->link_num == 0) {
queue(&lnk->t20,rx_up_wait, COLLTIME, lnk);
}
}
}
else {
if (newstate == 5) /* Connected */ {
lnk->R=R0;
lnk->coll=0;
if ((i=lnk->link_num) != 0) /* Level 3 Link */ {
if (i < L3SIZ) lnk->maxvc=L3_MAXVC[i];
queue(&lnk->t20 ,rsrtco ,(oldstate == 1) ? COLLTIME : 0 ,lnk);
}
else /* Level 2 User, wait for PID (in I frame) */ {
lnk->r_upcall=rx_up_wait;
/* Give L3 User 60 Sec to sent restart */
queue(&lnk->t20 ,rx_up_wait ,COLLTIME ,lnk);
}
}
else {
if (newstate == 1) /* Disconnect occurred */ {
c = Out_of_Order;
if (lnk->parms->retry && !lnk->n2cnt) {
c = Congestion+146;
} else if (lnk->rpid != PID_X25) c += 33;
while (vc=lnk->llcn) /* For all VC's */ {
vc_clear(vc,c);
}
c = lnk->link_num;
del_ax25(lnk);
route_fail(c); /* Advance pending calls if we can */
}
}
}
return 1;
}
void
rx_up_wait(axcb)
register struct axcb *axcb;
{
static struct datastr *p;
struct datastr *frag_pkt();
void level3();
kill(axcb->t20); /* Timer timed out, or isn't needed anymore */
if (axcb->rpid != PID_X25) /* Users don't listen to directions!! */ {
rx_up_ignore(axcb);
lnk_ign_fcn(axcb);
axcb->parms=l2parms;
p=frag_pkt(dup_pkt(l2_user_info), l2parms->framesize);
l2_copy(axcb, &p, 0x7fff);
}
else /* Hey! We've got a new Level 3 User!! */ {
lnk_l3_pars(axcb);
/* l3_st_up(axcb,1,5); /* Force into connected state */
level3(axcb); /* Process the data we received */
}
}
void
rx_up_ignore(axcb)
struct axcb *axcb;
{
static struct datastr *p;
recv_ax25(axcb,&p,0); /* Throw away the data */
free_pkt(p);
}
void
tx_up_flush(axcb)
register struct axcb *axcb;
{
if ( (axcb->iqueue == NULL) || (axcb->icnt <= 0) ) /* All done! */ {
close_ax25(axcb);
}
}
int
st_up_wait(axcb,old,new)
struct axcb *axcb;
unsigned char old,new;
{
puthex2("wait",axcb,"->",new);
if (new == 1) /* We are done!! */ {
del_ax25(axcb);
}
return 1;
}
int
NULLFCN() {}
struct datastr *
l_message(str, v)
char *str;
int v;
{
register struct datastr *p;
if ((p=mkpkt(str)) == NULL) return NULL;
putxch(p,(v>>8));
putxch(p,(v&0xff));
bappch(p,0x0d);
return p;
}
int
send_l3(vc, bp)
struct VCS *vc;
struct datastr *bp;
{
if (vc && vc->SEND) return (*vc->SEND)(vc, bp);
else free_pkt(bp);
return 0;
}
int
l3_reset(vc,diag)
struct VCS *vc;
unsigned int diag;
{
puthex2("l3reset",vc,"",diag);
tx_rst(vc, DTE_Orig+diag);
}
int
l2_reset(vc,diag)
struct VCS *vc;
unsigned int diag;
{
static struct axcb *lnk;
set_d(vc, D1, 0);
if ((lnk=vc->parent)) {
axconnect(lnk);
send_tnc(lnk,l_message("\r*** Reset *** ", diag));
}
}
int
l3_clear(vc,c)
register struct VCS *vc;
int c;
{
/* This should only set P1 if no parent, see l3_st_up re: CLRONRESET */
if (vc->parent) tx_clr(vc,c);
else set_p(vc, P1, 0);
/* Insert code to generate call clear records here */
}
int
l3_connected(vc)
struct VCS *vc;
{
/* Insert code to generate call records here */
}
int
l2_clear(vc,c)
struct VCS *vc;
unsigned int c;
{
register struct axcb *lnk;
lnk=vc->parent;
set_p(vc,P1,0);
if (!lnk) return; /* No link exists */
lnk_ign_fcn(lnk);
if (lnk->state < 3) close_ax25(lnk);
else send_tnc(lnk,l_message("\r*** Disconnect *** ", c));
}
tnc_attempt(axcb, vcp)
struct axcb *axcb;
register struct VCS *vcp;
{
extern char being_set[];
send_tnc(axcb, mkpkt(
(vcp->alt && !(vcp->flags & CLRONRESET) && vcp->P == P1) ?
being_set : "") );
}
int
l2_con(vc)
register struct VCS *vc;
{
static struct datastr *bp;
static struct axcb *axcb;
static unsigned char *ch;
int call_str(), x121_str();
extern char complete[];
void l2_rx_up();
/* if (vc) if (vc->RECV) (*vc->RECV)(vc,NULL); */
axcb = vc->parent;
if (!vc->alt && !(vc->flags & CLRONRESET) && axcb) {
bp = mkpkt(complete);
ch = &str_work[call_str(&vc->parent->myaddr, str_work)];
*ch++ = ' ';
*ch++ = '@';
*ch++ = ' ';
ch += x121_str(vc->peer->addr, ch);
*ch++ = 0x0d;
*ch = 0;
bappstr(bp,str_work);
send_tnc(axcb, bp);
}
queue(NULL, l2_rx_up, 0, axcb);
}
int
l2_send(vcx, px)
struct VCS *vcx;
struct datastr *px;
{
register struct axcb *lnk;
static struct VCS *vc;
static int frsiz, windo;
vc_queue_data((vc=vcx),px); /* We were passed data */
if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
lnk=vc->parent;
frsiz = lnk->parms->framesize;
windo = frsiz * lnk->parms->maxframe; /* Number of bytes I can send */
l2_copy(lnk, &vc->tx_queue, windo);
if (lnk->window <= lnk->icnt) return 0; /* Can't accept any more now */
return frsiz; /* Return what we can take now */
}
l2_copy(lnk, bpq, w)
struct axcb *lnk;
register struct datastr **bpq;
int w;
{
static struct datastr *p;
while (p = *bpq) /* More to send */ {
if (w <= lnk->icnt) return;
*bpq = p->next;
p->next=NULL;
send_tnc(lnk,p);
}
}
int
l2_recv(vcx,pkt)
struct VCS *vcx;
struct datastr *pkt;
{
register struct VCS *vcp;
static struct VCS *vc;
static struct axcb *lnk;
static struct datastr *p;
static int i;
int recv_ax25();
vc=vcx;
if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
lnk=vc->parent;
if ((vcp=vc->peer)) /* Have a peer */ {
i = send_l3(vcp,NULL);
vc->LBUSY = !i;
while (!vc->LBUSY) /* And they can take more! */ {
if (recv_ax25(lnk,&p,i) <= 0) break;
i = send_l3(vcp,p);
vc->LBUSY = !i;
}
}
}
int
l3_send(vc,px)
register struct VCS *vc;
struct datastr *px;
{
static struct axcb *lnk;
static struct datastr *p, *p1;
static int frsiz, i;
puthex2("l3tx P",vc->P,"busy",vc->RBUSY);
vc_queue_data(vc,(p=px)); /* We have data to send */
if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
lnk=vc->parent;
if (vc->RBUSY) return 0; /* We are flow controlled */
while ( vc->tx_queue && /* We have data to send AND */
((vc->LIPR + vc->WI - vc->OPS) % 8) > 0 ) /* Window is open */ {
i= (vc->OPS << 1) + (vc->OPR << 5);
if ((p1=new_buffer(3)) == NULL) break; /* No memory */
bappch(p1,0x10); /* GFI=1 LCGN=0 */
bappch(p1,vc->lcn);
bappch(p1,i); /* p(r) 0 p(s) 0 Packet type */
p=vc->tx_queue;
vc->tx_queue=p->next;
p->next=NULL;
p1=binsert(p1,p);
l2_tx(lnk,p1); /* Send the frame */
vc->OPS = (vc->OPS +1) % 8;
}
frsiz=lnk->parms->framesize;
if (((vc->LIPR + vc->WI - vc->OPS) % 8) > 0 ) /* Window open */ i=frsiz;
else i=0; /* Window Closed can't take any more */
return i;
}
int
l3_recv(vc, pkt)
register struct VCS *vc;
struct datastr *pkt;
{
static char lbusy;
puthex2("l3rx",vc,"",pkt);
if (vc->P != P4 || vc->D != D1) return 0; /* Not in data transfer! */
lbusy=vc->LBUSY;
vc->LBUSY = !send_l3(vc->peer, pkt);
if (lbusy && !vc->LBUSY) tx_rr(vc); /* Just got un-busy */
}
void
l2_rx_up(axcb)
struct axcb *axcb;
{
register struct VCS *vc;
if (vc=axcb->llcn) (*vc->RECV)(vc,NULL); /* Have a vc */
}
void
l2_tx_up(axcb)
struct axcb *axcb;
{
register struct VCS *vc;
void call_request();
if (vc=axcb->llcn) if (vc=vc->peer) {
if (vc->P == P1 && /* Source user connection setup */
vc->alt == 255 && /* Hasn't been through call_request */
!axcb->icnt) { /* Message is ack'ed */
queue(&vc->peer->timer,call_request,0,vc);
}
else (*vc->RECV)(vc,NULL);
}
}
vc_l2_pars(vc)
register struct VCS *vc;
{
extern int (*L2PARS[])();
bmove(&L2PARS, &vc->RESET, 5*sizeof(vc->RESET));
#if 0
11/1/89 vc->RESET=l2_reset;
vc->CLEAR=l2_clear;
vc->SEND=l2_send;
vc->RECV=l2_recv;
vc->CONNECTED=l2_con;
#endif
}
lnk_l3_pars(lnk)
register struct axcb *lnk;
{
static int i;
int l2_window(), find_call();
lnk->parms=l3parms;
lnk->r_upcall=level3;
lnk->t_upcall=NULLFCN;
lnk->s_upcall=l3_st_up;
lnk->window=l2_window(l3parms);
i = find_call(&lnk->path[0]);
if (i>0 && L3_MAXVC[i]) {
lnk->link_num = i;
lnk->rpid = PID_X25;
}
}
void
lnk_ign_fcn(lnk)
register struct axcb *lnk;
{
lnk->r_upcall=rx_up_ignore;
lnk->t_upcall=tx_up_flush;
lnk->s_upcall=st_up_wait;
}
void
vc_clear(vc,c)
register struct VCS *vc;
int c;
{
if (vc->peer) {
vc->peer->peer = NULL;
set_p(vc->peer,P6,c);
vc->peer = NULL;
}
set_p(vc,P1,0);
}
int
vc_reset(vc, c)
register struct VCS *vc;
int c;
{
static unsigned char flag;
flag = vc->flags; /* This CAN call P6 if CLRONRESET is set */
set_d(vc,D3, c);
if (!(flag&CLRONRESET)) set_d(vc,D1, 0);
}